
import { _rotate2, _o, isMatrix, _dis, _mid, _moveDis } from "../math/index.js"
import { isObject, _has, _type } from '../utils/index.js'
import { _mirror } from '../math/mirror.js'
import { newSeq } from '../math/arraySort.js'
import { getLeftPoints, getTopPoints, getRightPoints, getBottomPoints, getBoundingClientRectPoints } from './shapeRect.js'
import { angleMapFn } from './angle.js'
// 外圈顶点
export const _borderPoints = (matrix, mirror) => {
    let index = isObject(mirror) ? mirror.borderIndex : 0
    let len = matrix.length
    return matrix[(index >= len || index <= 0) ? (len - 1) : index]
}
// 镜像点
const _mirrorPoint = (point, index, mirrorPoints) => {
    return mirrorPoints ? mirrorPoints[index % mirrorPoints.length] : point
}

const _none = (points) => {
    return points || []
}
const _seq = (ps, i) => {
    let len = ps.length
    return newSeq(ps, i % len)
}
const _refraction = (refraction, i, len) => {
    if (typeof refraction === 'function') {
        let ra = refraction(0, i, len).a
        return ra
    }
    return refraction

}
const _vertexOneline = (points, { scale, refraction, departure = 0, onelineOffset }, mirrorPoints) => {
    let result = []
    let len = points.length
    let o = mirrorPoints ? _o(mirrorPoints) : _o(points)
    points.forEach((t, i) => {
        let mp = _mirrorPoint(t, i, mirrorPoints)
        mp = _moveDis(mp, o, departure)
        let ra = _refraction(refraction, i, len)
        let ps = _mirror(points, mp, scale, ra)
        result.push(t)
        result.push(..._seq(ps, i + onelineOffset))
    })
    return result
}

const _vertexMirror = (points, { scale, refraction, departure = 0 }, mirrorPoints) => {

    let o = mirrorPoints ? _o(mirrorPoints) : _o(points)
    let len = points.length
    let ps = points.map((t, i) => {
        let mp = _mirrorPoint(t, i, mirrorPoints)
        mp = _moveDis(mp, o, departure)
        let ra = _refraction(refraction, i, len)
        let ps = _mirror(points, mp, scale, ra)
        return ps
    })
    return [points, ...ps]
}
const _edgeOneline = (points, { scale, refraction, onelineOffset, departure = 0 }, mirrorPoints) => {
    let result = []
    let o = mirrorPoints ? _o(mirrorPoints) : _o(points)
    let ms = _mid(points)
    let mms = mirrorPoints ? _mid(mirrorPoints) : null
    let len = points.length
    ms.forEach((t, i) => {
        let mp = _mirrorPoint(t, i, mms)
        mp = _moveDis(mp, o, departure)
        let ra = _refraction(refraction, i, len)
        let ps = _mirror(points, mp, scale, ra)
        result.push(points[i])
        result.push(..._seq(ps, i + onelineOffset))
    })
    return result
}
const _edgeMirror = (points, { scale, refraction, departure = 0 }, mirrorPoints) => {
    let o = mirrorPoints ? _o(mirrorPoints) : _o(points)
    let ms = _mid(points)
    let mms = mirrorPoints ? _mid(mirrorPoints) : null
    let len = points.length
    let ps = ms.map((t, i) => {
        let mp = _mirrorPoint(t, i, mms)
        mp = _moveDis(mp, o, departure)
        let ra = _refraction(refraction, i, len)
        let ps = _mirror(points, mp, scale, ra)
        return ps
    })
    return [points, ...ps]
}
const _edgeMidOneline = (points, { scale, refraction, onelineOffset, departure = 0 }, mirrorPoints) => {
    let result = []
    let len = points.length
    let ms = _mid(points)
    let mms = mirrorPoints ? _mid(mirrorPoints) : null
    let o = mirrorPoints ? _o(mirrorPoints) : _o(points)
    ms.forEach((t, i) => {
        let mp = _mirrorPoint(t, i, mms)
        mp = _moveDis(mp, o, departure)
        let ra = _refraction(refraction, i, len)
        let ps = _mirror(ms, mp, scale, ra)
        result.push(points[i])
        result.push(..._seq(ps, i + onelineOffset))
    })
    return result
}
const _edgeMidMirror = (points, { scale, refraction, departure = 0 }, mirrorPoints) => {
    let len = points.length
    let ms = _mid(points)
    let mms = mirrorPoints ? _mid(mirrorPoints) : null
    let o = mirrorPoints ? _o(mirrorPoints) : _o(points)
    let ps = ms.map((t, i) => {
        let mp = _mirrorPoint(t, i, mms)
        mp = _moveDis(mp, o, departure)
        let ra = _refraction(refraction, i, len)
        let ps = _mirror(ms, mp, scale, ra)
        return ps
    })
    return [points, ...ps]
}



const _radiusMidOneline = (points, { scale, refraction, onelineOffset, departure = 0 }, mirrorPoints) => {
    let result = []
    let len = points.length
    let o = mirrorPoints ? _o(mirrorPoints) : _o(points)
    points.forEach((t, i) => {
        let mp = _mirrorPoint(t, i, mirrorPoints)
        mp = _moveDis(mp, o, departure)
        let rm = _mid(mp, o)
        let ra = _refraction(refraction, i, len)
        let ps = _mirror(points, rm, scale, ra)
        result.push(t)
        result.push(..._seq(ps, i + onelineOffset))
    })
    return result
}
const _radiusMidMirror = (points, { scale, refraction, departure = 0 }, mirrorPoints) => {
    let len = points.length
    let o = mirrorPoints ? _o(mirrorPoints) : _o(points)
    let ps = points.map((t, i) => {
        let mp = _mirrorPoint(t, i, mirrorPoints)
        mp = _moveDis(mp, o, departure)
        let rm = _mid(mp, o)
        let ra = _refraction(refraction, i, len)
        let ps = _mirror(points, rm, scale, ra)
        return ps
    })
    return [points, ...ps]
}

const _leftVertexMirror = (points, { scale, refraction, departure = 0 }, mirrorPoints) => {
    let p = getLeftPoints(points)
    let o = mirrorPoints ? _o(mirrorPoints) : _o(points)
    let len = points.length
    p = _moveDis(p, o, departure)
    // let mp = _mirrorPoint(t, i, mirrorPoints)
    let ra = _refraction(refraction, 1, len)
    let ps = _mirror(points, p, scale, ra)
    return [points, ps]
}
const _topVertexMirror = (points, { scale, refraction, departure = 0 }, mirrorPoints) => {
    let p = getTopPoints(points)
    let o = mirrorPoints ? _o(mirrorPoints) : _o(points)
    p = _moveDis(p, o, departure)
    let len = points.length
    let ra = _refraction(refraction, 1, len)
    let ps = _mirror(points, p, scale, ra)
    return [points, ps]
}

const _rightVertexMirror = (points, { scale, refraction, departure = 0 }, mirrorPoints) => {
    let p = getRightPoints(points)
    let o = mirrorPoints ? _o(mirrorPoints) : _o(points)
    p = _moveDis(p, o, departure)
    let len = points.length
    let ra = _refraction(refraction, 1, len)
    let ps = _mirror(points, p, scale, ra)
    return [points, ps]
}

const _bottomVertexMirror = (points, { scale, refraction, departure = 0 }, mirrorPoints) => {
    let p = getBottomPoints(points)
    let o = mirrorPoints ? _o(mirrorPoints) : _o(points)
    p = _moveDis(p, o, departure)
    let len = points.length
    let ra = _refraction(refraction, 1, len)
    let ps = _mirror(points, p, scale, ra)
    return [points, ps]
}

const _rectVertexMirror = (points, { scale, refraction, departure = 0 }, mirrorPoints) => {
    let len = points.length
    let o = mirrorPoints ? _o(mirrorPoints) : _o(points)
    let { top, right, bottom, left } = getBoundingClientRectPoints(points)
    let ps = [top, right, bottom, left].map((t, i) => {
        let mp = _mirrorPoint(t, i, mirrorPoints)
        mp = _moveDis(mp, o, departure)
        let ra = _refraction(refraction, i, len)
        let ps = _mirror(points, mp, scale, ra)
        return ps
    })
    return [points, ...ps]
}

const onelineMapFn = {
    none: _none,
    vertex: _vertexOneline,
    edge: _edgeOneline,
    edgeMid: _edgeMidOneline,
    radiusMid: _radiusMidOneline,
    leftVertex: _leftVertexMirror,
    topVertex: _topVertexMirror,
    rightVertex: _rightVertexMirror,
    bottomVertex: _bottomVertexMirror,
    rectVertex: _rectVertexMirror
}

const mirrorMapFn = {
    none: _none,
    vertex: _vertexMirror,
    edge: _edgeMirror,
    edgeMid: _edgeMidMirror,
    radiusMid: _radiusMidMirror,
    leftVertex: _leftVertexMirror,
    topVertex: _topVertexMirror,
    rightVertex: _rightVertexMirror,
    bottomVertex: _bottomVertexMirror,
    rectVertex: _rectVertexMirror
}

export const mirrorTypes = Object.keys(mirrorMapFn)

// 镜像迭代 一笔画
export const _onelinePoints = (type, points, options, mirrorPoints) => {

    let fn = onelineMapFn[type] || _none
    return fn(points, options, mirrorPoints)
}
// 镜像迭代
export const _mirrorIterPoints = (type, points, options, mirrorPoints) => {
    let fn = mirrorMapFn[type] || _none
    return fn(points, options, mirrorPoints)
}

// 镜像点
export const _mirrorPoints = (points, mirror, mirrorPoints) => {
    if (isMatrix(points)) {
        let mirrorPoints = _borderPoints(points, mirror)
        return points.map(t => {
            return _mirrorPoints(t, mirror, mirrorPoints)
        })
    }

    let type, scale, oneline = false, onelineOffset = 1,
        refraction = 0, departure = 0
    if (isObject(mirror)) {
        type = mirror.type
        scale = mirror.scale || 1
        oneline = mirror.oneline
        onelineOffset = mirror.onelineOffset
        refraction = angleMapFn[mirror.refraction] || mirror.refraction
        departure = mirror.departure


    } else {
        type = mirror
    }
    let fn = oneline ? _onelinePoints : _mirrorIterPoints
    return fn(type, points, { scale, onelineOffset, refraction, departure }, mirrorPoints)
}

export const mirrorRefractions = Object.keys(angleMapFn)